library(mosaic)
library(tidyverse)
library(lubridate)
library(DataComputing)
library(rvest)
library(broom)

Research Focus:

As COVID-19 spreads at an alarming rate, a pressing question at a global scale emerges– what factors of a country contribute to the spread of Coronavirus. We hope to analyze the relationship between a country’s population level, population density, and continent categorization on the spread of COVID-19.

Data Access

Reading in the Data:

Data Source 1: COVID

COVID <- read.csv(file = "total-covid-cases-deaths-per-million.csv")
COVID
COVID %>%
  nrow()
[1] 9487
COVID %>%
  names()
  [1] "total.covid.cases.deaths.per.million" "X"                                    "X.1"                                 
  [4] "X.2"                                  "X.3"                                  "X.4"                                 
  [7] "X.5"                                  "X.6"                                  "X.7"                                 
 [10] "X.8"                                  "X.9"                                  "X.10"                                
 [13] "X.11"                                 "X.12"                                 "X.13"                                
 [16] "X.14"                                 "X.15"                                 "X.16"                                
 [19] "X.17"                                 "X.18"                                 "X.19"                                
 [22] "X.20"                                 "X.21"                                 "X.22"                                
 [25] "X.23"                                 "X.24"                                 "X.25"                                
 [28] "X.26"                                 "X.27"                                 "X.28"                                
 [31] "X.29"                                 "X.30"                                 "X.31"                                
 [34] "X.32"                                 "X.33"                                 "X.34"                                
 [37] "X.35"                                 "X.36"                                 "X.37"                                
 [40] "X.38"                                 "X.39"                                 "X.40"                                
 [43] "X.41"                                 "X.42"                                 "X.43"                                
 [46] "X.44"                                 "X.45"                                 "X.46"                                
 [49] "X.47"                                 "X.48"                                 "X.49"                                
 [52] "X.50"                                 "X.51"                                 "X.52"                                
 [55] "X.53"                                 "X.54"                                 "X.55"                                
 [58] "X.56"                                 "X.57"                                 "X.58"                                
 [61] "X.59"                                 "X.60"                                 "X.61"                                
 [64] "X.62"                                 "X.63"                                 "X.64"                                
 [67] "X.65"                                 "X.66"                                 "X.67"                                
 [70] "X.68"                                 "X.69"                                 "X.70"                                
 [73] "X.71"                                 "X.72"                                 "X.73"                                
 [76] "X.74"                                 "X.75"                                 "X.76"                                
 [79] "X.77"                                 "X.78"                                 "X.79"                                
 [82] "X.80"                                 "X.81"                                 "X.82"                                
 [85] "X.83"                                 "X.84"                                 "X.85"                                
 [88] "X.86"                                 "X.87"                                 "X.88"                                
 [91] "X.89"                                 "X.90"                                 "X.91"                                
 [94] "X.92"                                 "X.93"                                 "X.94"                                
 [97] "X.95"                                 "X.96"                                 "X.97"                                
[100] "X.98"                                 "X.99"                                 "X.100"                               
[103] "X.101"                                "X.102"                                "X.103"                               
[106] "X.104"                                "X.105"                                "X.106"                               
[109] "X.107"                                "X.108"                                "X.109"                               
[112] "X.110"                                "X.111"                                "X.112"                               
[115] "X.113"                                "X.114"                                "X.115"                               
[118] "X.116"                                "X.117"                                "X.118"                               
[121] "X.119"                                "X.120"                                "X.121"                               
[124] "X.122"                                "X.123"                                "X.124"                               
[127] "X.125"                                "X.126"                                "X.127"                               
[130] "X.128"                                "X.129"                                "X.130"                               
[133] "X.131"                                "X.132"                                "X.133"                               
[136] "X.134"                                "X.135"                                "X.136"                               
[139] "X.137"                                "X.138"                                "X.139"                               
[142] "X.140"                                "X.141"                                "X.142"                               
[145] "X.143"                                "X.144"                                "X.145"                               
[148] "X.146"                                "X.147"                                "X.148"                               
[151] "X.149"                                "X.150"                                "X.151"                               
[154] "X.152"                                "X.153"                                "X.154"                               
[157] "X.155"                                "X.156"                                "X.157"                               
[160] "X.158"                                "X.159"                                "X.160"                               
[163] "X.161"                                "X.162"                                "X.163"                               
[166] "X.164"                                "X.165"                                "X.166"                               
[169] "X.167"                                "X.168"                                "X.169"                               
[172] "X.170"                                "X.171"                                "X.172"                               
[175] "X.173"                                "X.174"                                "X.175"                               
[178] "X.176"                                "X.177"                                "X.178"                               
[181] "X.179"                                "X.180"                                "X.181"                               
[184] "X.182"                                "X.183"                                "X.184"                               
[187] "X.185"                                "X.186"                                "X.187"                               
[190] "X.188"                                "X.189"                                "X.190"                               
[193] "X.191"                                "X.192"                                "X.193"                               
[196] "X.194"                                "X.195"                                "X.196"                               
[199] "X.197"                                "X.198"                                "X.199"                               
[202] "X.200"                                "X.201"                                "X.202"                               
[205] "X.203"                                "X.204"                                "X.205"                               
[208] "X.206"                                "X.207"                                "X.208"                               
[211] "X.209"                                "X.210"                                "X.211"                               
[214] "X.212"                                "X.213"                                "X.214"                               
[217] "X.215"                                "X.216"                                "X.217"                               
[220] "X.218"                                "X.219"                                "X.220"                               
[223] "X.221"                                "X.222"                                "X.223"                               
[226] "X.224"                                "X.225"                                "X.226"                               
[229] "X.227"                                "X.228"                                "X.229"                               
[232] "X.230"                                "X.231"                                "X.232"                               
[235] "X.233"                                "X.234"                                "X.235"                               
[238] "X.236"                                "X.237"                                "X.238"                               
[241] "X.239"                                "X.240"                                "X.241"                               
[244] "X.242"                                "X.243"                                "X.244"                               
[247] "X.245"                                "X.246"                                "X.247"                               
[250] "X.248"                                "X.249"                                "X.250"                               
[253] "X.251"                                "X.252"                                "X.253"                               
[256] "X.254"                               
COVID %>%
  head()

Data Source 2: CountryData

CountryData
CountryData %>%
  nrow()
[1] 256
CountryData %>%
  names()
 [1] "country"           "area"              "pop"               "growth"            "birth"             "death"            
 [7] "migr"              "maternal"          "infant"            "life"              "fert"              "health"           
[13] "HIVrate"           "HIVpeople"         "HIVdeath"          "obesity"           "underweight"       "educ"             
[19] "unemploymentYouth" "GDP"               "GDPgrowth"         "GDPcapita"         "saving"            "indProd"          
[25] "labor"             "unemployment"      "family"            "tax"               "budget"            "debt"             
[31] "inflation"         "discount"          "lending"           "narrow"            "broad"             "credit"           
[37] "shares"            "balance"           "exports"           "imports"           "gold"              "externalDebt"     
[43] "homeStock"         "abroadStock"       "elecProd"          "elecCons"          "elecExp"           "elecImp"          
[49] "elecCap"           "elecFossil"        "elecNuc"           "elecHydro"         "elecRenew"         "oilProd"          
[55] "oilExp"            "oilImp"            "oilRes"            "petroProd"         "petroCons"         "petroExp"         
[61] "petroImp"          "gasProd"           "gasCons"           "gasExp"            "gasImp"            "gasRes"           
[67] "mainlines"         "cell"              "netHosts"          "netUsers"          "airports"          "railways"         
[73] "roadways"          "waterways"         "marine"            "military"         
CountryData %>%
  head()

Data Source 3: countryRegions

countryRegions
countryRegions %>%
  nrow()
[1] 254
countryRegions %>%
  names()
 [1] "ISO3"         "ADMIN"        "REGION"       "continent"    "GEO3major"    "GEO3"         "IMAGE24"      "GLOCAF"      
 [9] "Stern"        "SRESmajor"    "SRES"         "GBD"          "AVOIDnumeric" "AVOIDname"    "LDC"          "SID"         
[17] "LLDC"        
countryRegions %>%
  head()

Data Wrangling

Tidying the COVID Dataset

COVID

Since our analysis is focused on the spread of COVID-19, we select only columns which pertain to the number of COVID-19 cases in countries over time.

TidyCOVID <- COVID %>%
  rename(country = total.covid.cases.deaths.per.million ) %>%
  rename( Code = X ) %>%
  rename(date = X.1 ) %>%
  rename(casesPerMillion = X.3) %>%
  filter(row_number() > 1) %>%
  subset(select = c(1,2,3,5)) %>%
  mutate( country = as.character(country) ) %>%
  mutate(date = mdy(date)) %>%
  mutate(casesPerMillion = as.integer(casesPerMillion) - 1)
TidyCOVID

EVELYN pls explain what an instance represents

Wrangling of countryRegions Dataset

We will extract the ISO3 country code and continent from the countryRegions data. Since naming conventions of countries is variate, the ISO3 country code allows us a standardized demarcation of country with which to join with other data tables.

Labels <-
  countryRegions %>%
  subset(select = c("ISO3", "REGION")) %>%
  rename(continent = REGION)
Labels

Data Extraction of CountryData Dataset

We will select the aspects of CountryData relevant to our analysis. These attributes are: area (sq km) and pop (number of people).

RelevantCountryData <-
  CountryData %>%
  subset(select = c(1,2,3)) %>%
  mutate(popdensity = pop/area)
RelevantCountryData

Joining Data & Relevant Variable Synthesis

Calculate the number of cases in each country by multiplying casesPerMillion by the country’s population (in millions).

COVIDGrowth <-
  inner_join(TidyCOVID, RelevantCountryData, by = c("country")) %>%
  mutate("cases" = (casesPerMillion * round(pop/1000000, digits = 0)))
COVIDGrowth <-
  COVIDGrowth %>%
  left_join(Labels, by = c("Code" = "ISO3"))
Column `Code`/`ISO3` joining factor and character vector, coercing into character vector
COVIDGrowth

Creation of new Data Table: FirstInstance

This table records the first date that a country recorded a nonzero number of COVID-19 cases. This datagraph will help us visualize when countries first became infected.

FirstInstance <-
  COVIDGrowth %>%
  filter(cases != 0) %>%
  group_by(country, continent) %>%
  summarise(beginningofspread = min(date))
  
FirstInstance

This table averages the number of case increase per day from the first day a country had COVID-19 to the most recent in the data table (April 5 2020)

DailySpread <-
  left_join(COVIDGrowth, FirstInstance, by = c("country")) %>%
  filter(date == "2020-04-05") %>%
  mutate(dayselapsed = date - beginningofspread) %>%
  mutate(dailyspread = cases / as.numeric(dayselapsed) ) %>%
  mutate(dailyspreadpermillion = casesPerMillion / as.numeric(dayselapsed) ) %>%
  subset(select = c("country", "beginningofspread", "dailyspread", "dailyspreadpermillion"))
DailySpread$dailyspread[is.na(DailySpread$dailyspread)] <- 0
DailySpread$dailyspreadpermillion[is.na(DailySpread$dailyspreadpermillion)] <- 0
DailySpread
COVIDFinal <-
  left_join(COVIDGrowth, DailySpread, by = c("country"))
COVIDFinal

Data Visualization

Overall Growth of COVID-19 Over Time

COVIDFinal %>%
  group_by(date) %>%
  summarise(totalcases = sum(cases)) %>%
  ggplot(aes(x = date, y = totalcases)) + 
  geom_point() +
  xlab("Date") +
  ylab("COVID-19 Cases")

Continental Growth of COVID-19 Over Time

na.omit(COVIDFinal) %>%
  group_by(date, continent) %>%
  summarise(totalcases = sum(cases)) %>%
  ggplot(aes(x = date, y = totalcases)) + 
  geom_point() +
  facet_wrap(~continent) +
  xlab("Date") +
  ylab("COVID-19 Cases")

Infection of COVID-19 into countries over time

na.omit(FirstInstance) %>%
  ggplot(aes(x = beginningofspread, fill = continent)) +
  geom_dotplot(stackgroups = TRUE, binwidth = 1, binpositions="all") +
  xlab("Country's First Case of COVID-19") +
  theme(panel.background = element_blank(),
        axis.text.y = element_blank(),
        axis.ticks.y = element_blank(),
        axis.title.y = element_blank())

Which countries have the highest infection rates?

  
COVIDFinal %>%
  group_by(country) %>%
  summarise(dailyspread = mean(dailyspread)) %>%
  arrange(desc(dailyspread)) %>%
  head(20) %>%
  ggplot(aes(x = reorder(country, desc(dailyspread)), y= dailyspread)) +
  geom_bar(stat="identity", position = 'stack', width=.9) +
  theme(axis.text.x=element_text(angle = 60, hjust = 1)) +
  scale_y_continuous(labels = function(x) format(x, scientific = FALSE)) +
  ylab("Average Number Infected Per Day") +
  theme(axis.title.x = element_blank())

Compare this to which countries have the highest populations

COVIDFinal %>%
  group_by(country) %>%
  summarise(pop = mean(pop)) %>%
  arrange(desc(pop)) %>%
  head(20) %>%
  ggplot(aes(x = reorder(country, desc(pop)), y= pop)) +
  geom_bar(stat="identity", position = 'stack', width=.9) +
  theme(axis.text.x=element_text(angle = 60, hjust = 1)) +
  scale_y_continuous(labels = function(x) format(x, scientific = FALSE)) +
  ylab("Population") +
  theme(axis.title.x = element_blank())

Let’s visualize the relationship between population and COVID-19 spread on the same data frame… with an awareness of the continental distribution

na.omit(COVIDFinal) %>%
  ggplot(aes(x = pop, y = dailyspread, color = continent)) + 
  geom_point() +
  xlab("Population of Country") +
  ylab("Average Number Infected Per Day")

Does the relationship hold up after removing the largest outliers (China and India)?

Does the positive relationship hold up across all continents?

na.omit(COVIDFinal) %>%
  ggplot(aes(x = pop, y = dailyspread, color = continent)) + 
  geom_point() +
  xlim(0,500000000) +
  ylim(0, 40000) +
  xlab("Population of Country") +
  ylab("Average Number Infected Per Day") +
  stat_smooth(method = lm) 

A prevailing explanation for the spread of COVID-19 is social closeness, therefore, we hypothesize that countries with the highest population density will have the highest proportional rates of infection. To measure the proportional rates of infection, it is essential to use a standardized metric, such that the data is not skewed towards the countries with simply the most people. Therefore, we will analyze the variable “population per million infected per day”, which captures a representation of the percentage of a country’s population that is effective. If our hypothesis is correct, the countries with the highest population per million infected per day will be those with the highest population density.

Which countries have the highest infection rates per million?

  
COVIDFinal %>%
  group_by(country) %>%
  summarise(dailyspreadpermillion = mean(dailyspreadpermillion)) %>%
  arrange(desc(dailyspreadpermillion)) %>%
  head(20) %>%
  ggplot(aes(x = reorder(country, desc(dailyspreadpermillion)), y= dailyspreadpermillion)) +
  geom_bar(stat="identity", position = 'stack', width=.9) +
  theme(axis.text.x=element_text(angle = 60, hjust = 1)) +
  scale_y_continuous(labels = function(x) format(x, scientific = FALSE)) +
  ylab("Population Per Million Infected Per Day") +
  theme(axis.title.x = element_blank())

Which countries have the highest population density?

  
COVIDFinal %>%
  group_by(country) %>%
  summarise(popdensity = mean(popdensity)) %>%
  arrange(desc(popdensity)) %>%
  head(20) %>%
  ggplot(aes(x = reorder(country, desc(popdensity)), y= popdensity)) +
  geom_bar(stat="identity", position = 'stack', width=.9) +
  theme(axis.text.x=element_text(angle = 60, hjust = 1)) +
  scale_y_continuous(labels = function(x) format(x, scientific = FALSE)) +
  ylab("Population Density (people/sq km)") +
  theme(axis.title.x = element_blank())

Is there a visible correlation between these attributes?

na.omit(COVIDFinal) %>%
  ggplot(aes(x = popdensity, y = dailyspreadpermillion)) +
  geom_point() 

What if faceted by continent?

na.omit(COVIDFinal) %>%
  ggplot(aes(x = popdensity, y = dailyspreadpermillion)) +
  geom_point() + 
  facet_wrap(~continent) + 
  xlim(0,1500)

Conclusion

evelyn pls write a conclusion here… something about there being a correlation btwn population and spread, but once standardized, the correlation is far less evident… we can not prove a correlation between population density and infection rate/million.

also i defined this function (because we need a user defined function and to use wide/narrow form), but unsure exactly where to put it,, lmk if u think of a good place.

Country Comparison Function

Easy to Traverse– Wide Countries

WideCountries <-
  COVIDFinal %>%
  subset(select = c("country", "date", "cases")) %>%
  spread(key = date, value = cases)
WideCountries[is.na(WideCountries)] <- 0
WideCountries

compareCOVID() definition

compareCOVID <- function(countryA, countryB) {
  
    A <-
    WideCountries %>%
    filter(country == countryA)
  
  B <-
    WideCountries %>%
    filter(country == countryB)
  A <-
    A %>%
    gather(key = date, value = count) %>%
    filter(row_number() > 1) %>%
    mutate(date = lubridate::ymd(date)) %>%
    mutate(count = as.numeric(count)) %>%
    mutate(country = countryA)
  
  B <-
    B %>%
    gather(key = date, value = count) %>%
    filter(row_number() > 1) %>%
    mutate(date = lubridate::ymd(date))%>%
    mutate(count = as.numeric(count)) %>%
    mutate(country = countryB)
  
  
  GG <-
    rbind(A,B)
  
  return( ggplot(GG, aes(x = date, y = count, color = country)) +
    stat_smooth(formula = y ~ x, method = "loess") +
      ylab("Number of COVID-19 Cases") +
      xlab("Date"))
  
}

Ex. of compareCOVID() in use:

compareCOVID("China", "United States")

compareCOVID("Japan", "Russia")

compareCOVID("Puerto Rico", "Belgium")

LS0tCnRpdGxlOiAiRmluYWwgUHJvamVjdCIKb3V0cHV0OiBodG1sX25vdGVib29rCmF1dGhvcnM6ICJKb3NlcGggUGV2bmVyIGFuZCBFdmVseW4gTXVycmF5IgotLS0KCmBgYHtyfQpsaWJyYXJ5KG1vc2FpYykKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkobHVicmlkYXRlKQpsaWJyYXJ5KERhdGFDb21wdXRpbmcpCmxpYnJhcnkocnZlc3QpCmxpYnJhcnkoYnJvb20pCmBgYAoKIyMgUmVzZWFyY2ggRm9jdXM6CgpBcyBDT1ZJRC0xOSBzcHJlYWRzIGF0IGFuIGFsYXJtaW5nIHJhdGUsIGEgcHJlc3NpbmcgcXVlc3Rpb24gYXQgYSBnbG9iYWwgc2NhbGUgZW1lcmdlcy0tIHdoYXQgZmFjdG9ycyBvZiBhIGNvdW50cnkgY29udHJpYnV0ZSB0byB0aGUgc3ByZWFkIG9mIENvcm9uYXZpcnVzLiBXZSBob3BlIHRvIGFuYWx5emUgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGEgY291bnRyeSdzIHBvcHVsYXRpb24gbGV2ZWwsIHBvcHVsYXRpb24gZGVuc2l0eSwgYW5kIGNvbnRpbmVudCBjYXRlZ29yaXphdGlvbiBvbiB0aGUgc3ByZWFkIG9mIENPVklELTE5LgoKCgojIyBEYXRhIEFjY2VzcwoKIyMjIFJlYWRpbmcgaW4gdGhlIERhdGE6CgoKIyMjIyBEYXRhIFNvdXJjZSAxOiBDT1ZJRApgYGB7cn0KQ09WSUQgPC0gcmVhZC5jc3YoZmlsZSA9ICJ0b3RhbC1jb3ZpZC1jYXNlcy1kZWF0aHMtcGVyLW1pbGxpb24uY3N2IikKQ09WSUQKYGBgCgpgYGB7cn0KQ09WSUQgJT4lCiAgbnJvdygpCmBgYApgYGB7cn0KQ09WSUQgJT4lCiAgbmFtZXMoKQpgYGAKYGBge3J9CkNPVklEICU+JQogIGhlYWQoKQpgYGAKCgoKIyMjIyBEYXRhIFNvdXJjZSAyOiBDb3VudHJ5RGF0YQpgYGB7cn0KQ291bnRyeURhdGEKYGBgCgpgYGB7cn0KQ291bnRyeURhdGEgJT4lCiAgbnJvdygpCmBgYApgYGB7cn0KQ291bnRyeURhdGEgJT4lCiAgbmFtZXMoKQpgYGAKYGBge3J9CkNvdW50cnlEYXRhICU+JQogIGhlYWQoKQpgYGAKCiMjIyMgRGF0YSBTb3VyY2UgMzogY291bnRyeVJlZ2lvbnMKCmBgYHtyfQpjb3VudHJ5UmVnaW9ucwpgYGAKYGBge3J9CmNvdW50cnlSZWdpb25zICU+JQogIG5yb3coKQpgYGAKYGBge3J9CmNvdW50cnlSZWdpb25zICU+JQogIG5hbWVzKCkKYGBgCmBgYHtyfQpjb3VudHJ5UmVnaW9ucyAlPiUKICBoZWFkKCkKYGBgCgoKCgojIyBEYXRhIFdyYW5nbGluZwoKIyMjIFRpZHlpbmcgdGhlIENPVklEIERhdGFzZXQKCmBgYHtyfQpDT1ZJRApgYGAKClNpbmNlIG91ciBhbmFseXNpcyBpcyBmb2N1c2VkIG9uIHRoZSBzcHJlYWQgb2YgQ09WSUQtMTksIHdlIHNlbGVjdCBvbmx5IGNvbHVtbnMgd2hpY2ggcGVydGFpbiB0byB0aGUgbnVtYmVyIG9mIENPVklELTE5IGNhc2VzIGluIGNvdW50cmllcyBvdmVyIHRpbWUuCgpgYGB7cn0KVGlkeUNPVklEIDwtIENPVklEICU+JQogIHJlbmFtZShjb3VudHJ5ID0gdG90YWwuY292aWQuY2FzZXMuZGVhdGhzLnBlci5taWxsaW9uICkgJT4lCiAgcmVuYW1lKCBDb2RlID0gWCApICU+JQogIHJlbmFtZShkYXRlID0gWC4xICkgJT4lCiAgcmVuYW1lKGNhc2VzUGVyTWlsbGlvbiA9IFguMykgJT4lCiAgZmlsdGVyKHJvd19udW1iZXIoKSA+IDEpICU+JQogIHN1YnNldChzZWxlY3QgPSBjKDEsMiwzLDUpKSAlPiUKICBtdXRhdGUoIGNvdW50cnkgPSBhcy5jaGFyYWN0ZXIoY291bnRyeSkgKSAlPiUKICBtdXRhdGUoZGF0ZSA9IG1keShkYXRlKSkgJT4lCiAgbXV0YXRlKGNhc2VzUGVyTWlsbGlvbiA9IGFzLmludGVnZXIoY2FzZXNQZXJNaWxsaW9uKSAtIDEpCgoKYGBgCgoKYGBge3J9ClRpZHlDT1ZJRAoKYGBgCgoKCkVWRUxZTiBwbHMgZXhwbGFpbiB3aGF0IGFuIGluc3RhbmNlIHJlcHJlc2VudHMKCgojIyMgV3JhbmdsaW5nIG9mIGNvdW50cnlSZWdpb25zIERhdGFzZXQKCldlIHdpbGwgZXh0cmFjdCB0aGUgSVNPMyBjb3VudHJ5IGNvZGUgYW5kIGNvbnRpbmVudCBmcm9tIHRoZSBjb3VudHJ5UmVnaW9ucyBkYXRhLiBTaW5jZSBuYW1pbmcgY29udmVudGlvbnMgb2YgY291bnRyaWVzIGlzIHZhcmlhdGUsIHRoZSBJU08zIGNvdW50cnkgY29kZSBhbGxvd3MgdXMgYSBzdGFuZGFyZGl6ZWQgZGVtYXJjYXRpb24gb2YgY291bnRyeSB3aXRoIHdoaWNoIHRvIGpvaW4gd2l0aCBvdGhlciBkYXRhIHRhYmxlcy4KCmBgYHtyfQpMYWJlbHMgPC0KICBjb3VudHJ5UmVnaW9ucyAlPiUKICBzdWJzZXQoc2VsZWN0ID0gYygiSVNPMyIsICJSRUdJT04iKSkgJT4lCiAgcmVuYW1lKGNvbnRpbmVudCA9IFJFR0lPTikKCkxhYmVscwoKYGBgCgoKIyMjIERhdGEgRXh0cmFjdGlvbiBvZiBDb3VudHJ5RGF0YSBEYXRhc2V0CgpXZSB3aWxsIHNlbGVjdCB0aGUgYXNwZWN0cyBvZiBDb3VudHJ5RGF0YSByZWxldmFudCB0byBvdXIgYW5hbHlzaXMuIFRoZXNlIGF0dHJpYnV0ZXMgYXJlOiBhcmVhIChzcSBrbSkgYW5kIHBvcCAobnVtYmVyIG9mIHBlb3BsZSkuCgpgYGB7cn0KClJlbGV2YW50Q291bnRyeURhdGEgPC0KICBDb3VudHJ5RGF0YSAlPiUKICBzdWJzZXQoc2VsZWN0ID0gYygxLDIsMykpICU+JQogIG11dGF0ZShwb3BkZW5zaXR5ID0gcG9wL2FyZWEpCgpSZWxldmFudENvdW50cnlEYXRhCmBgYAoKIyMjIEpvaW5pbmcgRGF0YSAmIFJlbGV2YW50IFZhcmlhYmxlIFN5bnRoZXNpcwoKQ2FsY3VsYXRlIHRoZSBudW1iZXIgb2YgY2FzZXMgaW4gZWFjaCBjb3VudHJ5IGJ5IG11bHRpcGx5aW5nIGNhc2VzUGVyTWlsbGlvbiBieSB0aGUgY291bnRyeSdzIHBvcHVsYXRpb24gKGluIG1pbGxpb25zKS4gCmBgYHtyfQoKQ09WSURHcm93dGggPC0KICBpbm5lcl9qb2luKFRpZHlDT1ZJRCwgUmVsZXZhbnRDb3VudHJ5RGF0YSwgYnkgPSBjKCJjb3VudHJ5IikpICU+JQogIG11dGF0ZSgiY2FzZXMiID0gKGNhc2VzUGVyTWlsbGlvbiAqIHJvdW5kKHBvcC8xMDAwMDAwLCBkaWdpdHMgPSAwKSkpCgpDT1ZJREdyb3d0aCA8LQogIENPVklER3Jvd3RoICU+JQogIGxlZnRfam9pbihMYWJlbHMsIGJ5ID0gYygiQ29kZSIgPSAiSVNPMyIpKQoKQ09WSURHcm93dGgKYGBgCgojIyMgQ3JlYXRpb24gb2YgbmV3IERhdGEgVGFibGU6IEZpcnN0SW5zdGFuY2UKClRoaXMgdGFibGUgcmVjb3JkcyB0aGUgZmlyc3QgZGF0ZSB0aGF0IGEgY291bnRyeSByZWNvcmRlZCBhIG5vbnplcm8gbnVtYmVyIG9mIENPVklELTE5IGNhc2VzLiBUaGlzIGRhdGFncmFwaCB3aWxsIGhlbHAgdXMgdmlzdWFsaXplIHdoZW4gY291bnRyaWVzIGZpcnN0IGJlY2FtZSBpbmZlY3RlZC4KYGBge3J9CgpGaXJzdEluc3RhbmNlIDwtCiAgQ09WSURHcm93dGggJT4lCiAgZmlsdGVyKGNhc2VzICE9IDApICU+JQogIGdyb3VwX2J5KGNvdW50cnksIGNvbnRpbmVudCkgJT4lCiAgc3VtbWFyaXNlKGJlZ2lubmluZ29mc3ByZWFkID0gbWluKGRhdGUpKQogIApGaXJzdEluc3RhbmNlCgoKYGBgCgoKCgpUaGlzIHRhYmxlIGF2ZXJhZ2VzIHRoZSBudW1iZXIgb2YgY2FzZSBpbmNyZWFzZSBwZXIgZGF5IGZyb20gdGhlIGZpcnN0IGRheSBhIGNvdW50cnkgaGFkIENPVklELTE5IHRvIHRoZSBtb3N0IHJlY2VudCBpbiB0aGUgZGF0YSB0YWJsZSAoQXByaWwgNSAyMDIwKQoKYGBge3J9CgpEYWlseVNwcmVhZCA8LQogIGxlZnRfam9pbihDT1ZJREdyb3d0aCwgRmlyc3RJbnN0YW5jZSwgYnkgPSBjKCJjb3VudHJ5IikpICU+JQogIGZpbHRlcihkYXRlID09ICIyMDIwLTA0LTA1IikgJT4lCiAgbXV0YXRlKGRheXNlbGFwc2VkID0gZGF0ZSAtIGJlZ2lubmluZ29mc3ByZWFkKSAlPiUKICBtdXRhdGUoZGFpbHlzcHJlYWQgPSBjYXNlcyAvIGFzLm51bWVyaWMoZGF5c2VsYXBzZWQpICkgJT4lCiAgbXV0YXRlKGRhaWx5c3ByZWFkcGVybWlsbGlvbiA9IGNhc2VzUGVyTWlsbGlvbiAvIGFzLm51bWVyaWMoZGF5c2VsYXBzZWQpICkgJT4lCiAgc3Vic2V0KHNlbGVjdCA9IGMoImNvdW50cnkiLCAiYmVnaW5uaW5nb2ZzcHJlYWQiLCAiZGFpbHlzcHJlYWQiLCAiZGFpbHlzcHJlYWRwZXJtaWxsaW9uIikpCgpEYWlseVNwcmVhZCRkYWlseXNwcmVhZFtpcy5uYShEYWlseVNwcmVhZCRkYWlseXNwcmVhZCldIDwtIDAKRGFpbHlTcHJlYWQkZGFpbHlzcHJlYWRwZXJtaWxsaW9uW2lzLm5hKERhaWx5U3ByZWFkJGRhaWx5c3ByZWFkcGVybWlsbGlvbildIDwtIDAKCgpEYWlseVNwcmVhZApgYGAKCgoKYGBge3J9CgpDT1ZJREZpbmFsIDwtCiAgbGVmdF9qb2luKENPVklER3Jvd3RoLCBEYWlseVNwcmVhZCwgYnkgPSBjKCJjb3VudHJ5IikpCgoKYGBgCgoKCmBgYHtyfQpDT1ZJREZpbmFsCgpgYGAKCgoKCgoKCgojIyBEYXRhIFZpc3VhbGl6YXRpb24KCgojIyMgT3ZlcmFsbCBHcm93dGggb2YgQ09WSUQtMTkgT3ZlciBUaW1lCmBgYHtyfQoKQ09WSURGaW5hbCAlPiUKICBncm91cF9ieShkYXRlKSAlPiUKICBzdW1tYXJpc2UodG90YWxjYXNlcyA9IHN1bShjYXNlcykpICU+JQogIGdncGxvdChhZXMoeCA9IGRhdGUsIHkgPSB0b3RhbGNhc2VzKSkgKyAKICBnZW9tX3BvaW50KCkgKwogIHhsYWIoIkRhdGUiKSArCiAgeWxhYigiQ09WSUQtMTkgQ2FzZXMiKQoKYGBgCgoKCgojIyMgQ29udGluZW50YWwgR3Jvd3RoIG9mIENPVklELTE5IE92ZXIgVGltZQoKYGBge3J9CgpuYS5vbWl0KENPVklERmluYWwpICU+JQogIGdyb3VwX2J5KGRhdGUsIGNvbnRpbmVudCkgJT4lCiAgc3VtbWFyaXNlKHRvdGFsY2FzZXMgPSBzdW0oY2FzZXMpKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBkYXRlLCB5ID0gdG90YWxjYXNlcykpICsgCiAgZ2VvbV9wb2ludCgpICsKICBmYWNldF93cmFwKH5jb250aW5lbnQpICsKICB4bGFiKCJEYXRlIikgKwogIHlsYWIoIkNPVklELTE5IENhc2VzIikKYGBgCgoKIyMjIEluZmVjdGlvbiBvZiBDT1ZJRC0xOSBpbnRvIGNvdW50cmllcyBvdmVyIHRpbWUKYGBge3J9CgpuYS5vbWl0KEZpcnN0SW5zdGFuY2UpICU+JQogIGdncGxvdChhZXMoeCA9IGJlZ2lubmluZ29mc3ByZWFkLCBmaWxsID0gY29udGluZW50KSkgKwogIGdlb21fZG90cGxvdChzdGFja2dyb3VwcyA9IFRSVUUsIGJpbndpZHRoID0gMSwgYmlucG9zaXRpb25zPSJhbGwiKSArCiAgeGxhYigiQ291bnRyeSdzIEZpcnN0IENhc2Ugb2YgQ09WSUQtMTkiKSArCiAgdGhlbWUocGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpKQpgYGAKCgoKCgojIyMgV2hpY2ggY291bnRyaWVzIGhhdmUgdGhlIGhpZ2hlc3QgaW5mZWN0aW9uIHJhdGVzPwoKCmBgYHtyfQogIApDT1ZJREZpbmFsICU+JQogIGdyb3VwX2J5KGNvdW50cnkpICU+JQogIHN1bW1hcmlzZShkYWlseXNwcmVhZCA9IG1lYW4oZGFpbHlzcHJlYWQpKSAlPiUKICBhcnJhbmdlKGRlc2MoZGFpbHlzcHJlYWQpKSAlPiUKICBoZWFkKDIwKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSByZW9yZGVyKGNvdW50cnksIGRlc2MoZGFpbHlzcHJlYWQpKSwgeT0gZGFpbHlzcHJlYWQpKSArCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICdzdGFjaycsIHdpZHRoPS45KSArCiAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGFuZ2xlID0gNjAsIGhqdXN0ID0gMSkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gZnVuY3Rpb24oeCkgZm9ybWF0KHgsIHNjaWVudGlmaWMgPSBGQUxTRSkpICsKICB5bGFiKCJBdmVyYWdlIE51bWJlciBJbmZlY3RlZCBQZXIgRGF5IikgKwogIHRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSkKCgoKYGBgCgojIyMgQ29tcGFyZSB0aGlzIHRvIHdoaWNoIGNvdW50cmllcyBoYXZlIHRoZSBoaWdoZXN0IHBvcHVsYXRpb25zCgpgYGB7cn0KCkNPVklERmluYWwgJT4lCiAgZ3JvdXBfYnkoY291bnRyeSkgJT4lCiAgc3VtbWFyaXNlKHBvcCA9IG1lYW4ocG9wKSkgJT4lCiAgYXJyYW5nZShkZXNjKHBvcCkpICU+JQogIGhlYWQoMjApICU+JQogIGdncGxvdChhZXMoeCA9IHJlb3JkZXIoY291bnRyeSwgZGVzYyhwb3ApKSwgeT0gcG9wKSkgKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgcG9zaXRpb24gPSAnc3RhY2snLCB3aWR0aD0uOSkgKwogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZSA9IDYwLCBoanVzdCA9IDEpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGZ1bmN0aW9uKHgpIGZvcm1hdCh4LCBzY2llbnRpZmljID0gRkFMU0UpKSArCiAgeWxhYigiUG9wdWxhdGlvbiIpICsKICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCkpCgoKYGBgCgoKIyMjIExldCdzIHZpc3VhbGl6ZSB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gcG9wdWxhdGlvbiBhbmQgQ09WSUQtMTkgc3ByZWFkIG9uIHRoZSBzYW1lIGRhdGEgZnJhbWUuLi4gd2l0aCBhbiBhd2FyZW5lc3Mgb2YgdGhlIGNvbnRpbmVudGFsIGRpc3RyaWJ1dGlvbgoKCmBgYHtyfQoKbmEub21pdChDT1ZJREZpbmFsKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBwb3AsIHkgPSBkYWlseXNwcmVhZCwgY29sb3IgPSBjb250aW5lbnQpKSArIAogIGdlb21fcG9pbnQoKSArCiAgeGxhYigiUG9wdWxhdGlvbiBvZiBDb3VudHJ5IikgKwogIHlsYWIoIkF2ZXJhZ2UgTnVtYmVyIEluZmVjdGVkIFBlciBEYXkiKQoKCgpgYGAKCgoKIyMjIERvZXMgdGhlIHJlbGF0aW9uc2hpcCBob2xkIHVwIGFmdGVyIHJlbW92aW5nIHRoZSBsYXJnZXN0IG91dGxpZXJzIChDaGluYSBhbmQgSW5kaWEpPwojIyMgRG9lcyB0aGUgcG9zaXRpdmUgcmVsYXRpb25zaGlwIGhvbGQgdXAgYWNyb3NzIGFsbCBjb250aW5lbnRzPwpgYGB7cn0KCm5hLm9taXQoQ09WSURGaW5hbCkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gcG9wLCB5ID0gZGFpbHlzcHJlYWQsIGNvbG9yID0gY29udGluZW50KSkgKyAKICBnZW9tX3BvaW50KCkgKwogIHhsaW0oMCw1MDAwMDAwMDApICsKICB5bGltKDAsIDQwMDAwKSArCiAgeGxhYigiUG9wdWxhdGlvbiBvZiBDb3VudHJ5IikgKwogIHlsYWIoIkF2ZXJhZ2UgTnVtYmVyIEluZmVjdGVkIFBlciBEYXkiKSArCiAgc3RhdF9zbW9vdGgobWV0aG9kID0gbG0pIAoKCgpgYGAKCgoKIyMjIEEgcHJldmFpbGluZyBleHBsYW5hdGlvbiBmb3IgdGhlIHNwcmVhZCBvZiBDT1ZJRC0xOSBpcyBzb2NpYWwgY2xvc2VuZXNzLCB0aGVyZWZvcmUsIHdlIGh5cG90aGVzaXplIHRoYXQgY291bnRyaWVzIHdpdGggdGhlIGhpZ2hlc3QgcG9wdWxhdGlvbiBkZW5zaXR5IHdpbGwgaGF2ZSB0aGUgaGlnaGVzdCBwcm9wb3J0aW9uYWwgcmF0ZXMgb2YgaW5mZWN0aW9uLiBUbyBtZWFzdXJlIHRoZSBwcm9wb3J0aW9uYWwgcmF0ZXMgb2YgaW5mZWN0aW9uLCBpdCBpcyBlc3NlbnRpYWwgdG8gdXNlIGEgc3RhbmRhcmRpemVkIG1ldHJpYywgc3VjaCB0aGF0IHRoZSBkYXRhIGlzIG5vdCBza2V3ZWQgdG93YXJkcyB0aGUgY291bnRyaWVzIHdpdGggc2ltcGx5IHRoZSBtb3N0IHBlb3BsZS4gVGhlcmVmb3JlLCB3ZSB3aWxsIGFuYWx5emUgdGhlIHZhcmlhYmxlICJwb3B1bGF0aW9uIHBlciBtaWxsaW9uIGluZmVjdGVkIHBlciBkYXkiLCB3aGljaCBjYXB0dXJlcyBhIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBwZXJjZW50YWdlIG9mIGEgY291bnRyeSdzIHBvcHVsYXRpb24gdGhhdCBpcyBlZmZlY3RpdmUuIElmIG91ciBoeXBvdGhlc2lzIGlzIGNvcnJlY3QsIHRoZSBjb3VudHJpZXMgd2l0aCB0aGUgaGlnaGVzdCBwb3B1bGF0aW9uIHBlciBtaWxsaW9uIGluZmVjdGVkIHBlciBkYXkgd2lsbCBiZSB0aG9zZSB3aXRoIHRoZSBoaWdoZXN0IHBvcHVsYXRpb24gZGVuc2l0eS4KCgojIyMgV2hpY2ggY291bnRyaWVzIGhhdmUgdGhlIGhpZ2hlc3QgaW5mZWN0aW9uIHJhdGVzIHBlciBtaWxsaW9uPwoKCmBgYHtyfQogIApDT1ZJREZpbmFsICU+JQogIGdyb3VwX2J5KGNvdW50cnkpICU+JQogIHN1bW1hcmlzZShkYWlseXNwcmVhZHBlcm1pbGxpb24gPSBtZWFuKGRhaWx5c3ByZWFkcGVybWlsbGlvbikpICU+JQogIGFycmFuZ2UoZGVzYyhkYWlseXNwcmVhZHBlcm1pbGxpb24pKSAlPiUKICBoZWFkKDIwKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSByZW9yZGVyKGNvdW50cnksIGRlc2MoZGFpbHlzcHJlYWRwZXJtaWxsaW9uKSksIHk9IGRhaWx5c3ByZWFkcGVybWlsbGlvbikpICsKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIHBvc2l0aW9uID0gJ3N0YWNrJywgd2lkdGg9LjkpICsKICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGUgPSA2MCwgaGp1c3QgPSAxKSkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBmdW5jdGlvbih4KSBmb3JtYXQoeCwgc2NpZW50aWZpYyA9IEZBTFNFKSkgKwogIHlsYWIoIlBvcHVsYXRpb24gUGVyIE1pbGxpb24gSW5mZWN0ZWQgUGVyIERheSIpICsKICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCkpCgoKCmBgYAoKIyMjIFdoaWNoIGNvdW50cmllcyBoYXZlIHRoZSBoaWdoZXN0IHBvcHVsYXRpb24gZGVuc2l0eT8KCmBgYHtyfQogIApDT1ZJREZpbmFsICU+JQogIGdyb3VwX2J5KGNvdW50cnkpICU+JQogIHN1bW1hcmlzZShwb3BkZW5zaXR5ID0gbWVhbihwb3BkZW5zaXR5KSkgJT4lCiAgYXJyYW5nZShkZXNjKHBvcGRlbnNpdHkpKSAlPiUKICBoZWFkKDIwKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSByZW9yZGVyKGNvdW50cnksIGRlc2MocG9wZGVuc2l0eSkpLCB5PSBwb3BkZW5zaXR5KSkgKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgcG9zaXRpb24gPSAnc3RhY2snLCB3aWR0aD0uOSkgKwogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZSA9IDYwLCBoanVzdCA9IDEpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGZ1bmN0aW9uKHgpIGZvcm1hdCh4LCBzY2llbnRpZmljID0gRkFMU0UpKSArCiAgeWxhYigiUG9wdWxhdGlvbiBEZW5zaXR5IChwZW9wbGUvc3Ega20pIikgKwogIHRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSkKCgoKYGBgCgoKCgojIyMgSXMgdGhlcmUgYSB2aXNpYmxlIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlc2UgYXR0cmlidXRlcz8KCgpgYGB7cn0KbmEub21pdChDT1ZJREZpbmFsKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBwb3BkZW5zaXR5LCB5ID0gZGFpbHlzcHJlYWRwZXJtaWxsaW9uKSkgKwogIGdlb21fcG9pbnQoKSAKYGBgCgoKIyMjIFdoYXQgaWYgZmFjZXRlZCBieSBjb250aW5lbnQ/CgpgYGB7cn0KbmEub21pdChDT1ZJREZpbmFsKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBwb3BkZW5zaXR5LCB5ID0gZGFpbHlzcHJlYWRwZXJtaWxsaW9uKSkgKwogIGdlb21fcG9pbnQoKSArIAogIGZhY2V0X3dyYXAofmNvbnRpbmVudCkgKyAKICB4bGltKDAsMTUwMCkKCmBgYAoKCgoKCgojIyBDb25jbHVzaW9uCgoKCmV2ZWx5biBwbHMgd3JpdGUgYSBjb25jbHVzaW9uIGhlcmUuLi4gc29tZXRoaW5nIGFib3V0IHRoZXJlIGJlaW5nIGEgY29ycmVsYXRpb24gYnR3biBwb3B1bGF0aW9uIGFuZCBzcHJlYWQsIGJ1dCBvbmNlIHN0YW5kYXJkaXplZCwgdGhlIGNvcnJlbGF0aW9uIGlzIGZhciBsZXNzIGV2aWRlbnQuLi4gd2UgY2FuIG5vdCBwcm92ZSBhIGNvcnJlbGF0aW9uIGJldHdlZW4gcG9wdWxhdGlvbiBkZW5zaXR5IGFuZCBpbmZlY3Rpb24gcmF0ZS9taWxsaW9uLgoKCmFsc28gaSBkZWZpbmVkIHRoaXMgZnVuY3Rpb24gKGJlY2F1c2Ugd2UgbmVlZCBhIHVzZXIgZGVmaW5lZCBmdW5jdGlvbiBhbmQgdG8gdXNlIHdpZGUvbmFycm93IGZvcm0pLCBidXQgdW5zdXJlIGV4YWN0bHkgd2hlcmUgdG8gcHV0IGl0LCwgbG1rIGlmIHUgdGhpbmsgb2YgYSBnb29kIHBsYWNlLgoKCgoKCiMjIENvdW50cnkgQ29tcGFyaXNvbiBGdW5jdGlvbgoKCiMjIyBFYXN5IHRvIFRyYXZlcnNlLS0gV2lkZSBDb3VudHJpZXMKCmBgYHtyfQoKV2lkZUNvdW50cmllcyA8LQogIENPVklERmluYWwgJT4lCiAgc3Vic2V0KHNlbGVjdCA9IGMoImNvdW50cnkiLCAiZGF0ZSIsICJjYXNlcyIpKSAlPiUKICBzcHJlYWQoa2V5ID0gZGF0ZSwgdmFsdWUgPSBjYXNlcykKCldpZGVDb3VudHJpZXNbaXMubmEoV2lkZUNvdW50cmllcyldIDwtIDAKCldpZGVDb3VudHJpZXMKCmBgYAoKIyMjIGNvbXBhcmVDT1ZJRCgpIGRlZmluaXRpb24KCmBgYHtyfQoKY29tcGFyZUNPVklEIDwtIGZ1bmN0aW9uKGNvdW50cnlBLCBjb3VudHJ5QikgewogIAogICAgQSA8LQogICAgV2lkZUNvdW50cmllcyAlPiUKICAgIGZpbHRlcihjb3VudHJ5ID09IGNvdW50cnlBKQogIAogIEIgPC0KICAgIFdpZGVDb3VudHJpZXMgJT4lCiAgICBmaWx0ZXIoY291bnRyeSA9PSBjb3VudHJ5QikKCiAgQSA8LQogICAgQSAlPiUKICAgIGdhdGhlcihrZXkgPSBkYXRlLCB2YWx1ZSA9IGNvdW50KSAlPiUKICAgIGZpbHRlcihyb3dfbnVtYmVyKCkgPiAxKSAlPiUKICAgIG11dGF0ZShkYXRlID0gbHVicmlkYXRlOjp5bWQoZGF0ZSkpICU+JQogICAgbXV0YXRlKGNvdW50ID0gYXMubnVtZXJpYyhjb3VudCkpICU+JQogICAgbXV0YXRlKGNvdW50cnkgPSBjb3VudHJ5QSkKICAKICBCIDwtCiAgICBCICU+JQogICAgZ2F0aGVyKGtleSA9IGRhdGUsIHZhbHVlID0gY291bnQpICU+JQogICAgZmlsdGVyKHJvd19udW1iZXIoKSA+IDEpICU+JQogICAgbXV0YXRlKGRhdGUgPSBsdWJyaWRhdGU6OnltZChkYXRlKSklPiUKICAgIG11dGF0ZShjb3VudCA9IGFzLm51bWVyaWMoY291bnQpKSAlPiUKICAgIG11dGF0ZShjb3VudHJ5ID0gY291bnRyeUIpCiAgCiAgCiAgR0cgPC0KICAgIHJiaW5kKEEsQikKICAKICByZXR1cm4oIGdncGxvdChHRywgYWVzKHggPSBkYXRlLCB5ID0gY291bnQsIGNvbG9yID0gY291bnRyeSkpICsKICAgIHN0YXRfc21vb3RoKGZvcm11bGEgPSB5IH4geCwgbWV0aG9kID0gImxvZXNzIikgKwogICAgICB5bGFiKCJOdW1iZXIgb2YgQ09WSUQtMTkgQ2FzZXMiKSArCiAgICAgIHhsYWIoIkRhdGUiKSkKICAKfQoKCgoKYGBgCgoKIyMjIEV4LiBvZiBjb21wYXJlQ09WSUQoKSBpbiB1c2U6CgpgYGB7cn0KCmNvbXBhcmVDT1ZJRCgiQ2hpbmEiLCAiVW5pdGVkIFN0YXRlcyIpCgpjb21wYXJlQ09WSUQoIkphcGFuIiwgIlJ1c3NpYSIpCgpjb21wYXJlQ09WSUQoIlB1ZXJ0byBSaWNvIiwgIkJlbGdpdW0iKQoKYGBgCgoKCg==